package com.github.anastr.speedviewlib;

import com.github.anastr.speedviewlib.components.Indicators.SpindleIndicator;
import com.github.anastr.speedviewlib.util.AttrSetUtils;
import com.github.anastr.speedviewlib.util.ResUtil;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.*;
import ohos.agp.text.Font;
import ohos.agp.utils.Color;
import ohos.agp.utils.Matrix;
import ohos.agp.utils.Point;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;

public class PointerSpeedometer extends Speedometer {

    private Path markPath = new Path();
    private Paint speedometerPaint = new Paint(),
            pointerPaint = new Paint(),
            pointerBackPaint = new Paint(),
            circlePaint = new Paint(),
            markPaint = new Paint();
    private RectFloat speedometerRect = new RectFloat();

    private int speedometerColor = 0xFFEEEEEE, pointerColor = 0xFFFFFFFF;

    private boolean withPointer = true;


    public PointerSpeedometer(Context context) {
        this(context, null);
    }

    public PointerSpeedometer(Context context, AttrSet attrSet) {
        this(context, attrSet, "");
    }

    public PointerSpeedometer(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        speedometerPaint.setAntiAlias(true);
        pointerPaint.setAntiAlias(true);
        pointerBackPaint.setAntiAlias(true);
        circlePaint.setAntiAlias(true);
        markPaint.setAntiAlias(true);

        init();
        initAttributeSet(context, attrSet);
    }

    @Override
    protected void defaultGaugeValues() {
        super.setTextColor(0xFFFFFFFF);
        super.setSpeedTextColor(0xFFFFFFFF);
        super.setUnitTextColor(0xFFFFFFFF);
        super.setSpeedTextSize(dpTOpx(24));
        super.setUnitTextSize(dpTOpx(11));
        super.setSpeedTextTypeface(new Font.Builder("myfont").setWeight(Font.BOLD).build());
    }

    @Override
    protected void defaultSpeedometerValues() {
        super.setIndicator(new SpindleIndicator(getContext())
                .setIndicatorWidth(dpTOpx(16))
                .setIndicatorColor(0xFFFFFFFF));
        super.setBackgroundCircleColor(0xff48cce9);
        super.setSpeedometerWidth(dpTOpx(10));
    }

    private void init() {
        speedometerPaint.setStyle(Paint.Style.STROKE_STYLE);
        speedometerPaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        markPaint.setStyle(Paint.Style.STROKE_STYLE);
        markPaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        markPaint.setStrokeWidth(dpTOpx(2));
        circlePaint.setColor(new Color(0xFFFFFFFF));
    }

    private void initAttributeSet(Context context, AttrSet attrs) {
        if (attrs == null) {
            initAttributeValue();
            return;
        }

        speedometerColor = AttrSetUtils.getAttrSetColorInt(attrs, "sv_speedometerColor", speedometerColor);
        pointerColor = AttrSetUtils.getAttrSetColorInt(attrs, "sv_pointerColor", pointerColor);
        circlePaint.setColor(AttrSetUtils.getAttrSetColor(attrs, "sv_centerCircleColor", circlePaint.getColor()));
        withPointer = AttrSetUtils.getBoolean(attrs, "sv_withPointer", withPointer);
        initAttributeValue();
    }

    private void initAttributeValue() {
        pointerPaint.setColor(new Color(pointerColor));
    }

    @Override
    protected void onSizeChange(int w, int h, int oldW, int oldH) {
        super.onSizeChange(w, h, oldW, oldH);
        float risk = getSpeedometerWidth() * .5f + dpTOpx(8) + getCustomPadding();
        speedometerRect = new RectFloat(risk, risk, getSize() - risk, getSize() - risk);

        updateRadial();
        updateBackgroundBitmap();
    }

    private void initDraw() {
        speedometerPaint.setStrokeWidth(getSpeedometerWidth());
        speedometerPaint.setShader(updateSweep(), Paint.ShaderType.SWEEP_SHADER);
        markPaint.setColor(new Color(getMarkColor()));
    }

    @Override
    public void onDrawComponent(Component component, Canvas canvas) {
        super.onDrawComponent(component, canvas);
        initDraw();

        canvas.drawArc(speedometerRect, new Arc(getStartDegree(), getEndDegree() - getStartDegree(), false), speedometerPaint);

        if (withPointer) {
            canvas.save();
            canvas.rotate(90 + getDegree(), getSize() * .5f, getSize() * .5f);
            canvas.drawCircle(getSize() * .5f, getSpeedometerWidth() * .5f + dpTOpx(8) + getCustomPadding()
                    , getSpeedometerWidth() * .5f + dpTOpx(8), pointerBackPaint);
            canvas.drawCircle(getSize() * .5f, getSpeedometerWidth() * .5f + dpTOpx(8) + getCustomPadding()
                    , getSpeedometerWidth() * .5f + dpTOpx(1), pointerPaint);
            canvas.restore();
        }

        drawSpeedUnitText(canvas);
        drawIndicator(canvas);

        int c = getCenterCircleColor();
        circlePaint.setColor(new Color(Color.argb((int) (Color.alpha(c) * .5f), ResUtil.red(c), ResUtil.green(c), ResUtil.blue(c))));
        canvas.drawCircle(getSize() * .5f, getSize() * .5f, getWidthPa() / 14f, circlePaint);
        circlePaint.setColor(new Color(c));
        canvas.drawCircle(getSize() * .5f, getSize() * .5f, getWidthPa() / 22f, circlePaint);

        drawNotes(canvas);
    }

    @Override
    protected void updateBackgroundBitmap() {
        Canvas c = createBackgroundBitmapCanvas();
        initDraw();

        markPath.reset();
        markPath.moveTo(getSize() * .5f, getSpeedometerWidth() + dpTOpx(8) + dpTOpx(4) + getCustomPadding());
        markPath.lineTo(getSize() * .5f, getSpeedometerWidth() + dpTOpx(8) + dpTOpx(4) + getCustomPadding() + getSize() / 60f);

        c.save();
        c.rotate(90f + getStartDegree(), getSize() * .5f, getSize() * .5f);
        float everyDegree = (getEndDegree() - getStartDegree()) * .111f;
        for (float i = getStartDegree(); i < getEndDegree() - (2f * everyDegree); i += everyDegree) {
            c.rotate(everyDegree, getSize() * .5f, getSize() * .5f);
            c.drawPath(markPath, markPaint);
        }
        c.restore();

        if (getTickNumber() > 0)
            drawTicks(c);
        else
            drawDefMinMaxSpeedPosition(c);
    }

    private SweepShader updateSweep() {
        int startColor = Color.argb(150, ResUtil.red(speedometerColor), ResUtil.green(speedometerColor), ResUtil.blue(speedometerColor));
        int color2 = Color.argb(220, ResUtil.red(speedometerColor), ResUtil.green(speedometerColor), ResUtil.blue(speedometerColor));
        int color3 = Color.argb(70, ResUtil.red(speedometerColor), ResUtil.green(speedometerColor), ResUtil.blue(speedometerColor));
        int endColor = Color.argb(15, ResUtil.red(speedometerColor), ResUtil.green(speedometerColor), ResUtil.blue(speedometerColor));
        float position = getOffsetSpeed() * (getEndDegree() - getStartDegree()) / 360f;
        Color[] colors = new Color[]{new Color(startColor), new Color(color2), new Color(speedometerColor), new Color(color3), new Color(endColor), new Color(startColor)};
        SweepShader sweepGradient = new SweepShader(getSize() * .5f, getSize() * .5f
                , colors
                , new float[]{0f, position * .5f, position, position, .99f, 1f});
        Matrix matrix = new Matrix();
        matrix.postRotate(getStartDegree(), getSize() * .5f, getSize() * .5f);
        sweepGradient.setShaderMatrix(matrix);
        return sweepGradient;
    }

    private void updateRadial() {
        int centerColor = Color.argb(160, ResUtil.red(pointerColor), ResUtil.green(pointerColor), ResUtil.blue(pointerColor));
        int edgeColor = Color.argb(10, ResUtil.red(pointerColor), ResUtil.green(pointerColor), ResUtil.blue(pointerColor));
        Color[] colors = new Color[]{new Color(centerColor), new Color(edgeColor)};
        RadialShader pointerGradient = new RadialShader(new Point(getSize() * .5f, getSpeedometerWidth() * .5f + dpTOpx(8) + getCustomPadding()), getSpeedometerWidth() * .5f + dpTOpx(8), new float[]{.4f, 1f}, colors, Shader.TileMode.CLAMP_TILEMODE);
        pointerBackPaint.setShader(pointerGradient, Paint.ShaderType.RADIAL_SHADER);
    }

    public int getSpeedometerColor() {
        return speedometerColor;
    }

    public void setSpeedometerColor(int speedometerColor) {
        this.speedometerColor = speedometerColor;
        invalidate();
    }

    public int getPointerColor() {
        return pointerColor;
    }

    public void setPointerColor(int pointerColor) {
        this.pointerColor = pointerColor;
        pointerPaint.setColor(new Color(pointerColor));
        updateRadial();
        invalidate();
    }

    public int getCenterCircleColor() {
        return circlePaint.getColor().getValue();
    }

    /**
     * change the color of the center circle (if exist),
     * <b>this option is not available for all Speedometers</b>.
     *
     * @param centerCircleColor new color.
     */
    public void setCenterCircleColor(int centerCircleColor) {
        circlePaint.setColor(new Color(centerCircleColor));
        if (!isAttachedToWindow())
            return;
        invalidate();
    }

    public boolean isWithPointer() {
        return withPointer;
    }

    /**
     * enable to draw circle pointer on speedometer arc.<br>
     * this will not make any change for the Indicator.
     *
     * @param withPointer true: draw the pointer,
     *                    false: don't draw the pointer.
     */
    public void setWithPointer(boolean withPointer) {
        this.withPointer = withPointer;
        if (!isAttachedToWindow())
            return;
        invalidate();
    }

    /**
     * this Speedometer doesn't use this method.
     *
     * @return {@code Color.TRANSPARENT} always.
     */
    @Deprecated
    @Override
    public int getLowSpeedColor() {
        return 0;
    }

    /**
     * this Speedometer doesn't use this method.
     *
     * @param lowSpeedColor nothing.
     */
    @Deprecated
    @Override
    public void setLowSpeedColor(int lowSpeedColor) {
    }

    /**
     * this Speedometer doesn't use this method.
     *
     * @return {@code Color.TRANSPARENT} always.
     */
    @Deprecated
    @Override
    public int getMediumSpeedColor() {
        return 0;
    }

    /**
     * this Speedometer doesn't use this method.
     *
     * @param mediumSpeedColor nothing.
     */
    @Deprecated
    @Override
    public void setMediumSpeedColor(int mediumSpeedColor) {
    }

    /**
     * this Speedometer doesn't use this method.
     *
     * @return {@code Color.TRANSPARENT} always.
     */
    @Deprecated
    @Override
    public int getHighSpeedColor() {
        return 0;
    }

    /**
     * this Speedometer doesn't use this method.
     *
     * @param highSpeedColor nothing.
     */
    @Deprecated
    @Override
    public void setHighSpeedColor(int highSpeedColor) {
    }
}
